#pragma once

#include <iostream>
#include <sys/epoll.h>
#include <stdlib.h>

#include "log.hpp"
#include "comm.hpp"

using namespace log_namespace;

// 可以写成继承的方式，将select, epoll 

static const int gsize = 128;

class Multiplex
{
public:
    virtual bool addEvent(int fd, uint32_t events) = 0;

    // 下面的 声明 select 和 poll 并不能用
    virtual int wait(struct epoll_event revs[], int num, int timeout) = 0;
    virtual bool ModiEvent(int fd, uint32_t events) = 0;
    virtual bool DelEvent(int fd) = 0;
};

class Epoll : public Multiplex
{
private:
    // ④.2
    bool auxiModEvent(int fd, uint32_t events, int oper)
    {
        struct epoll_event ev;
        ev.events = events;
        ev.data.fd = fd; // 通过这个字段，向上触发
        int n = ::epoll_ctl(_epfd, oper, fd, &ev);
        if (n < 0)
        {
            LOG(ERROR, "Fail!!! epoll_ctl add %d, event is : %s\n", fd, eventsToString(events).c_str());
            return false;
        }
        LOG(INFO, "Success!!! epoll_ctl add %d, event is : %s\n", fd, eventsToString(events).c_str());
        return true;
    }
public:
    Epoll()
    {
        _epfd = ::epoll_create(gsize);
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll control error\n");
            exit(EPOLL_CREATE_ERROR);
        }
        LOG(INFO, "epoll create success, epfd: %d\n", _epfd);
    }

    std::string eventsToString(uint32_t events)
    {
        std::string eventstr;
        if (events & EPOLLIN)
        {
            eventstr = "EPOLLIN";
        }
        if (events & EPOLLOUT)
        {
            eventstr += "|EPOLLOUT";
        }
        if (events & EPOLLET)
        {
            eventstr += "|EPOLLET";
        }
        return eventstr;
    }

    // ④.1
    bool addEvent(int fd, uint32_t events) override
    {
        return auxiModEvent(fd, events, EPOLL_CTL_ADD);
    }    

    bool ModiEvent(int fd, uint32_t events) override
    {
        return auxiModEvent(fd, events, EPOLL_CTL_MOD);
    }

    bool DelEvent(int fd) override
    {
        return 0 == ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
    }

    // ⑤
    int wait(struct epoll_event revs[], int num, int timeout)
    {
        // revs这个结构体数组管理了很多对象，
        // 只要内核有就绪事件，revs就会将这些放到自己的数组中
        return ::epoll_wait(_epfd, revs, num, timeout); 
    }

    ~Epoll()
    {

    }
private:
    int _epfd;
};

// class Select : Multiplex
// {

// };

// class Poll : Multiplex
// {

// };
